package routers

import (
	"log"
	"strconv"
	"sync"
)

type Node struct {
	no     int
	length int
	paths  []int
}

func (n *Node) Less(other interface{}) bool {
	return n.length < other.(*Node).length
}

type InitMessage struct {
	no         RouterId
	neighbours map[RouterId]chan<- interface{}
}

type DropoutMessage struct {
	no RouterId
}

func Router(self RouterId, incoming <-chan interface{}, neighbours map[RouterId]chan<- interface{}, framework chan<- Envelope, totalRouters uint64) {
	var rwLock sync.RWMutex
	var iptables = make(map[RouterId]map[RouterId]chan<- interface{})
	iptables[self] = neighbours
	go sendNeighbours(neighbours, InitMessage{no: self, neighbours: neighbours})
	var optimalPaths [][]int
	for {
		select {
		case raw := <-incoming:
			switch msg := raw.(type) {
			case Shutdown:
				//优雅的关闭路由
				go sendNeighbours(neighbours, DropoutMessage{self})
				for i := 0; i < len(iptables); i++ {
					delete(iptables, RouterId(i))
				}
				iptables = nil
				for i := 0; i < len(optimalPaths); i++ {
					optimalPaths[i] = nil
				}
				optimalPaths = nil
				return
			case Envelope:
				if msg.Dest == self {
					framework <- msg
				} else {
					msg.Hops += 1
					sendMsg(rwLock, msg, self, int(totalRouters), &iptables, &optimalPaths)
				}
			case InitMessage:
				//初始化路由表
				_, ok := iptables[msg.no]
				if ok {
					continue
				}
				addIptables(rwLock, &iptables, msg)
				go sendNeighbours(neighbours, InitMessage{no: msg.no, neighbours: msg.neighbours})
				if len(iptables) == int(totalRouters) {
					initEndCaculate(rwLock, self, int(totalRouters), &optimalPaths, iptables)
				}
			case DropoutMessage:
				//路由掉线通知
				_, ok := iptables[msg.no]
				if !ok {
					continue
				}
				go sendNeighbours(neighbours, DropoutMessage{msg.no})
				updateIptablesCaculateSendMsg(rwLock, self, int(totalRouters), int(msg.no), &iptables, &optimalPaths, false)

			default:
				log.Printf("[%v] received unexpected message %g\n", self, msg)
			}
		//default:
		//	time.Sleep(10*time.Millisecond)
		}
	}
}
//发送消息
func sendMsg(rwLock sync.RWMutex, msg Envelope, self RouterId, totalRouters int, iptables *map[RouterId]map[RouterId]chan<- interface{}, optimalPaths *[][]int) {
	if optimalPaths == nil {
		initEndCaculate(rwLock, self, totalRouters, optimalPaths, *iptables)
	}
	paths := (*optimalPaths)[int(msg.Dest)]
	if len(paths) == 0 {
		log.Printf("router:[%v] arrive router:[%v] disconnect\n", self, msg.Dest)
		return
	}
	channal, ok := (*iptables)[self][RouterId(paths[0])]
	sikpUpdate := false
	var err error
	if !ok {
		sikpUpdate = true
	} else {
		err = sendMessage(channal, msg)
	}
	if !ok || err != nil {
		updateIptablesCaculateSendMsg(rwLock, self, totalRouters, paths[0], iptables, optimalPaths, sikpUpdate)
		sendMsg(rwLock, msg, self, totalRouters, iptables, optimalPaths)
	}
}
//更新路由表
func updateIptablesCaculateSendMsg(rwLock sync.RWMutex, self RouterId, totalRouters int, dropoutRouter int, iptables *map[RouterId]map[RouterId]chan<- interface{}, optimalPaths *[][]int, skipUpdate bool) {
	if !skipUpdate {
		rwLock.Lock()
		delete(*iptables, RouterId(dropoutRouter))
		tempIptables := make(map[RouterId]map[RouterId]chan<- interface{})
		for routerid, neighbours := range *iptables {
			tempIptables[routerid] = neighbours
		}
		for k, v := range tempIptables {
			for routerId, _ := range v {
				if routerId == RouterId(dropoutRouter) {
					delete((*iptables)[k], routerId)
				}
			}
		}
		rwLock.Unlock()
	}
	initEndCaculate(rwLock, self, totalRouters, optimalPaths, *iptables)
}

func addIptables(rwLock sync.RWMutex, iptables *map[RouterId]map[RouterId]chan<- interface{}, msg InitMessage) {
	rwLock.Lock()
	defer rwLock.Unlock()
	(*iptables)[msg.no] = msg.neighbours
}

func initEndCaculate(rwLock sync.RWMutex, self RouterId, totalRouters int, optimalPaths *[][]int, iptables map[RouterId]map[RouterId]chan<- interface{}) {
	tables := contructIptables(rwLock, totalRouters, iptables)
	caculatePaths(totalRouters, *tables, int(self), optimalPaths)
}

func sendNeighbours(neighbours map[RouterId]chan<- interface{}, message interface{}) {
	for routerid, channel := range neighbours {
		err := sendMessage(channel, message)
		if err != nil {
			log.Printf("router [%v] is closed \n", strconv.Itoa(int(routerid)))
		}
	}
}
//构造路由表
func contructIptables(rwLock sync.RWMutex, x int, iptables map[RouterId]map[RouterId]chan<- interface{}) (table *[][]int) {
	rwLock.Lock()
	defer rwLock.Unlock()
	contractTable := make([][]int, x)
	for i := range contractTable {
		contractTable[i] = make([]int, x)
		for j := 0; j < x; j++ {
			contractTable[i][j] = -1
		}
	}
	for routerid, neighbours := range iptables {
		for k, _ := range neighbours {
			contractTable[int(routerid)][int(k)] = 1
		}
	}
	return &contractTable
}
//找出最短的路径集合
func caculatePaths(x int, table [][]int, element int, optimalPaths *[][]int) {
	pathtable := make([][][]int, x)
	for i := range pathtable {
		pathtable[i] = make([][]int, x)
	}
	isconfirm := make([]bool, x)
	lenth := make([]int, x)
	for i := 0; i < len(lenth); i++ {
		lenth[i] = -1
	}
	priorityqueue := New()
	lenth[element] = 0
	priorityqueue.Push(&Node{
		no:     element,
		length: 0,
	})
	for {
		if priorityqueue.Len() == 0 {
			break
		}
		node := priorityqueue.Pop().(*Node)
		index := node.no
		length := node.length
		paths := node.paths
		isconfirm[index] = true
		for i := 0; i < len(table[index]); i++ {
			if table[index][i] > 0 && !isconfirm[i] {
				node1 := &Node{
					no:     i,
					length: length + table[index][i],
					paths:  append(paths, i),
				}
				if lenth[i] == -1 || lenth[i] > node1.length {
					pathtable[element][i] = node1.paths
					lenth[i] = node1.length
					priorityqueue.Push(node1)
				}
			}
		}
	}
	var tempPaths [][]int
	(*optimalPaths) = tempPaths
	for _, v := range pathtable[element] {
		(*optimalPaths) = append((*optimalPaths), v)
	}
	return
}


